#pragma once 

#include <iostream>
#include <string>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

const std::string cwd = "/";
const std::string dev = "/dev/null";

// 让网络服务器守护进程化
// 让启动的进程，独立成为一个进程组，并且占有独立的会话
// 守护进程化要求该进程不能是进程组的组长
void Daemon(int nochdir, int noclose)
{
    // 1. 守护进程忽略IO，以及子进程退出等相关信号
    signal(SIGPIPE, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);

    // 2.必须得是一个进程组的组员，不能是组长
    if(fork() > 0) exit(0);

    // 下面就是子进程，也就是组员进程
    // 2.5 守护进程话
    setsid();

    // 3.守护进程执行时需要将其当前的工作目录改为/根目录
    if(nochdir == 0) chdir(cwd.c_str());

    // 4.守护进程本质上是一个孤儿进程，后台进程
    // 要避免其使用0，1，2与终端交互
    // 所以，将0，1，2重定向到/dev/null文件，该文件会将写入的内容丢弃，从该文件读，会读到nullptr
    if(noclose == 0){
        int fd = open(dev.c_str(), O_RDWR); // 以读写方式打开

        // 重定向
        // int dup2(int oldfd, int newfd); // dup2会使用oldfd，覆盖newfd
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);
        close(fd);
    }
}